home *** CD-ROM | disk | FTP | other *** search
/ Aminet 33 / Aminet 33 - October 1999.iso / Aminet / misc / math / TCalcStats2c.lha / TCalcStats2c / AREXX / Normality.rexx < prev    next >
Encoding:
OS/2 REXX Batch file  |  1999-07-03  |  12.9 KB  |  697 lines

  1. /* Chi-Sq Goodness of Fit Normality Test */
  2.  
  3. options results
  4. if ~show('P','TCALC') then do
  5.     address command 'run turbocalc:turbocalc'
  6.     address command 'waitforport TCALC'
  7.     loadflag=1
  8. end
  9. address 'TCALC'
  10. 'DEFPUBSCREEN()'
  11. /* Add-in Rexx Math Library needed for some routines */
  12. signal on syntax
  13. if ~show('l','rexxmathlib.library') then
  14.    call addlib('rexxmathlib.library',0,-30)
  15. if ~show('l','rexxreqtools.library') then
  16.    call addlib('rexxreqtools.library',0,-30)
  17. if ~show('l','rexxsupport.library') then
  18.    call addlib('rexxsupport.library',0,-30)
  19.   /* add to library list */
  20. signal off syntax
  21.  
  22. /* Start Main Routine */
  23. if loadflag=1 then 'Load()'
  24. 'ActivateWindow()'
  25. range=rtgetstring(,"Enter Cell Range for Input","Input Request") /*,,'rt_pubscrname="TCALC"')*/
  26. colon=pos(":",range)
  27. if colon=0 then do
  28.     'Message "Please select a range before executing this script"'
  29.     'DEFPUBSCREEN("Workbench")'
  30.     exit
  31. end
  32.  
  33. /* Find cell references and cell, column numbers */
  34. start_cell=substr(range,1,colon-1)
  35. end_cell=substr(range,colon+1)
  36. start_row=cellrow(start_cell)
  37. end_row=cellrow(end_cell)
  38. start_col=cellcol(start_cell)
  39. end_col=cellcol(end_cell)
  40. NRows=end_row-start_row+1
  41. NCols=end_col-start_col+1
  42. If NCols>1 then do
  43.     'Message "Only one column of data allowed!"'
  44.     'DEFPUBSCREEN("Workbench")'
  45.     exit
  46. end
  47.  
  48. /* Get cell reference for output range */
  49. out_cell=rtgetstring(,"Enter Cell Reference for Output","Input Request") /*,,'rt_pubscrname="TCALC"')*/
  50. if out_cell="" then do
  51.     'DEFPUBSCREEN("Workbench")'
  52.     exit
  53. end
  54. if length(out_cell)<2 | datatype(left(out_cell,1),'n')=1 then do
  55.     'Message "Invalid cell reference"'
  56.     'DEFPUBSCREEN("Workbench")'
  57.     exit
  58. end
  59. BW=rtgetstring("0","Enter Desired Class Interval: 0 = Calculate","Input Request")
  60. BW=strip(BW)
  61. if rtresult=0 then DO
  62.     'DEFPUBSCREEN("Workbench")'
  63.     exit
  64. end
  65. min=rtgetstring("0","Enter First Lower Class Boundary: 0 = Calculate","Input Request")
  66. min=strip(min)
  67. if rtresult=0 then DO
  68.     'DEFPUBSCREEN("Workbench")'
  69.     exit
  70. end
  71. /* Suppress Screen Redraw to Speed Things Up */
  72. 'Refresh 0'
  73.  
  74. /* Open a small output window on tcalc screen*/
  75. fo=0
  76. CR='0a'x
  77. DisplayMsg="Calculating...Please Wait."||CR||"User input is disabled during calculation."||CR
  78. if open(6Info, 'con:100/0/450/80/Progress/SCREEN TCALC', w) then do
  79.      call writeln(6Info, DisplayMsg)
  80.     fo=1
  81. end
  82. else do
  83.     'Message "TCALC Screen not available for Progress messages"'
  84. end
  85. CALL DELAY(150)
  86.  
  87. /* Get cell references for top cell in each column */
  88. 'SelectCell' start_cell
  89. do col=start_col to end_col
  90.     'GetCursorPos'
  91.     top_cell.col=result
  92.     'Column 1'
  93. end
  94.  
  95. /* Get labels for later use on output */
  96. 'SelectCell' start_cell
  97. 'GetValue'
  98. testlabel=result
  99. testlabel=strip(testlabel)
  100. if datatype(testlabel,'n')=1 then do
  101.     labelflag=0
  102.     title="Column "||x
  103. end
  104. else do
  105.     labelflag=1
  106.     NRows=NRows-1
  107.     title=testlabel
  108. end
  109. if fo then call writech(6Info,"Progress...10 ")
  110.  
  111. /* Get data from cell range */
  112. col=start_col
  113. lav=0
  114. tot=0
  115. count=0
  116. total=0
  117. do x=1 to NCols
  118.     'SelectCell' top_cell.col
  119.     if labelflag=1 then 'CursorDown 1'
  120.     do y=1 to NRows
  121.         'GetValue'
  122.         valtest=result
  123.         if datatype(valtest)='NUM' then do
  124.             'GetValue'
  125.             val=result
  126.             val=strip(val)
  127.             data.y=val
  128.             total=total+val
  129.             count=1+count
  130.         end
  131.         'CursorDown 1'
  132.     end
  133. if fo then call writech(6Info,"20 ")
  134.  
  135. /* Calculate Mean and Standard Deviation */
  136. mean=0
  137. mean=total/count
  138. dat=0
  139. sum=0
  140. do y =1 to count
  141.     dat=data.y
  142.     sum=sum+(dat-mean)**2
  143. end
  144. N=count-1
  145. var=(sum)/N
  146. sd=sqrt(var)
  147. if fo then call writech(6Info,"30 ")
  148.  
  149. /* Sort Values */
  150. call Sort()
  151. if fo then call writech(6Info,"40 ")
  152.  
  153. /* Calculate Minimum, Maximum*/
  154. max=0
  155. N=count
  156. if min=0 then min=trunc(data.1)
  157. max=trunc(data.N+.5)
  158. if fo then call writech(6Info,"50 ")
  159.  
  160. /* Calculate lcb and ucb Range */
  161. cr='0a'x
  162. test=1
  163. x=1
  164. Nbins=0
  165. bin.=0
  166. ucb.=0
  167. if BW=0 then DO
  168.     Nbins=trunc(sqrt(count))
  169.     if Nbins<5 then Nbins=5
  170.     if Nbins>15 then Nbins=15
  171.     BW=(max-min)/Nbins
  172. End
  173. Else DO
  174.     Nbins=trunc((max-min)/BW)
  175.     if Nbins<5 then Nbins=5
  176.     if Nbins>15 then Nbins=15
  177. End
  178. if BW<.5 then cf=.0001
  179. if BW<1 & BW>=.5 then cf=.001
  180. if BW<10 & BW>=1 then cf=.01
  181. if BW<100 & BW>=10 then cf=.1
  182. if BW>=100 then cf=1
  183. lcb.1=min
  184. do x=2 to Nbins
  185.     z=x-1
  186.     lcb.x=(lcb.z)+BW
  187.     ucb.z=(lcb.x)-cf
  188. end
  189. if fo then call writech(6Info,"60 ")
  190.  
  191. /* Calculate Mean Deviation etc */
  192. meandev.=0
  193. stscore.=0
  194. Do y=Nbins-1 to 1 by -1
  195.     meandev.y=ucb.y-mean
  196.     stscore.y=(meandev.y)/sd
  197. End
  198. if fo then call writech(6Info,"70 ")
  199.  
  200. PBZ.=0
  201. PWZ.=0
  202. PBZ.Nbins=1
  203. Do y=Nbins-1 to 1 by -1
  204.     x=y+1
  205.     call NPROB(stscore.y)
  206.     PBZ.y=P
  207.     PWZ.x=(PBZ.x)-PBZ.y
  208. End
  209. if fo then call writech(6Info,"80 ")
  210.  
  211. PWZ.1=PBZ.1
  212. Do y=1 to Nbins
  213.     ExpFreq.y=PWZ.y*count
  214. End
  215.  
  216. /* Calculate Observed Frequencies */
  217. x=1
  218. freq.=0
  219. do y=1 to NRows
  220.     z=x+1
  221.     if x<Nbins then 
  222.     if (data.y)>=(lcb.x) & (data.y)<(lcb.z) then freq.x=(freq.x)+1
  223.     else do
  224.         y=y-1
  225.         x=x+1
  226.     end
  227.     else freq.x=(freq.x)+1
  228. end
  229.  
  230. /* Calculate Residuals and Chi-square */
  231. R.=0
  232. Chi=0
  233. D.=0
  234. DD=0
  235. Do y=1 to Nbins
  236.     DD=(freq.y)-(ExpFreq.y)
  237.     If DD=0 then DO
  238.         D.y=0
  239.         R.y=0
  240.     End
  241.     Else DO
  242.         D.y=(DD)**2
  243.         R.y=DD/sqrt(ExpFreq.y)
  244.     End
  245.     Chi=Chi+((D.y)/ExpFreq.y)
  246. end
  247. if fo then call writech(6Info,"60 ")
  248.  
  249. /* Degrees of Freedom? */
  250. w=rtgetlong(0,"Change df based on parameters estimated? - default=0","Value Required")
  251. if rtresult=0 then DO
  252.         'DEFPUBSCREEN("Workbench")'        
  253.         exit
  254. End
  255.  
  256. df=Nbins-1-w
  257. if df<1 then df=1
  258.  
  259. /* Calculate Probability */
  260. PC=CHIPROB(Chi,df)
  261. if fo then call writech(6Info,"80 ")
  262.  
  263. /* Calculate Critical */
  264. Chicrit1=CHICRIT(.95,df)
  265. if fo then call writech(6Info,"90 ")
  266. Chicrit2=CHICRIT(.99,DF)
  267. if fo then do
  268.     call writeln(6Info,"100")
  269.     call writeln(6Info,"Writing output to window...")
  270. end
  271.  
  272. /*Output*/
  273. 'SelectCell' out_cell
  274. 'ColumnWidth 18'
  275. 'Put "Chi-Sq Goodness of Fit of Normal Frequency Distribution"'
  276. 'CursorDown 2'
  277. title=""""||title||""""
  278. 'Put' title
  279. 'CursorDown 2'
  280. 'GetCursorPos'
  281. st_cell=result
  282. 'Alignment 2'
  283. 'Put "l.c.b"'
  284. 'Column 1'
  285. 'Alignment 2'
  286. 'Put "u.c.b"'
  287. 'Column 1'
  288. 'CursorUp 1'
  289. 'Alignment 2'
  290. 'Put "Mean"'
  291. 'CursorDown 1'
  292. 'Alignment 2'
  293. 'Put "Deviation"'
  294. 'Column 1'
  295. 'CursorUp 1'
  296. 'Alignment 2'
  297. 'Put "Standard"'
  298. 'CursorDown 1'
  299. 'Alignment 2'
  300. 'Put "Score"'
  301. 'Column 1'
  302. 'CursorUp 1'
  303. 'Alignment 2'
  304. 'Put "Proportion"'
  305. 'CursorDown 1'
  306. 'Alignment 2'
  307. 'Put "Within"'
  308. 'Column 1'
  309. 'CursorUp 1'
  310. 'Alignment 2'
  311. 'Put "Expected"'
  312. 'CursorDown 1'
  313. 'Alignment 2'
  314. 'Put "Frequency"'
  315. 'Column 1'
  316. 'CursorUp 1'
  317. 'Alignment 2'
  318. 'Put "Observed"'
  319. 'CursorDown 1'
  320. 'Alignment 2'
  321. 'Put "Frequency"'
  322. 'SelectCell' st_cell
  323. 'CursorDown 1'
  324. Do y=Nbins to 1 by -1
  325.     'Put' format(lcb.y,,2)
  326.     'CursorDown 1'
  327. End
  328. 'SelectCell' st_cell
  329. 'Column 1'
  330. 'CursorDown 2'
  331. Do y = Nbins-1 to 1 by -1
  332.     'Put' format(ucb.y,,2)
  333.     'CursorDown 1'
  334. End
  335. 'SelectCell' st_cell
  336. 'Column 2'
  337. 'CursorDown 2'
  338. Do y=Nbins-1 to 1 by -1
  339.     'Put' format(meandev.y,,2)
  340.     'CursorDown 1'
  341. End
  342. 'SelectCell' st_cell
  343. 'Column 3'
  344. 'CursorDown 2'
  345. Do y=Nbins-1 to 1 by -1
  346.     'Put' format(stscore.y,,4)
  347.     'CursorDown 1'
  348. End
  349. 'SelectCell' st_cell
  350. 'Column 4'
  351. 'CursorDown 1'
  352. Do y= Nbins to 1 by -1
  353.     'Put' format(PWZ.y,,4)
  354.     'CursorDown 1'
  355. End
  356. 'SelectCell' st_cell
  357. 'Column 5'
  358. 'CursorDown 1'
  359. Do y=Nbins to 1 by -1
  360.     'Put' format(ExpFreq.y,,2)
  361.     'CursorDown 1'
  362. End
  363. 'SelectCell' st_cell
  364. 'Column 6'
  365. 'CursorDown 1'
  366. Do y=Nbins to 1 by -1
  367.     'Put' format(freq.y,,2)
  368.     'CursorDown 1'
  369. End
  370. 'SelectCell' st_cell
  371. 'CursorDown' Nbins+3
  372. 'Put' "Chi-Square:"
  373. 'CursorDown 1'
  374. 'Put "d.f.:"'
  375. 'CursorDown 1'
  376. 'Put "P(CHI<=chi):"'
  377. 'CursorDown 1'
  378. 'Put "Chi-Critical (95%):"'
  379. 'CursorDown 1'
  380. 'Put "Chi-Critical (99%):"'
  381. 'CursorUp 4'
  382. 'Column 1'
  383. 'Put' format(Chi,,4)
  384. 'CursorDown 1'
  385. 'Put' df
  386. 'CursorDown 1'
  387. 'Put' format(PC,,6)
  388. 'CursorDown 1'
  389. 'Put' format(ChiCrit1,,4)
  390. 'CursorDown 1'
  391. 'Put' format(ChiCrit2,,4)
  392. 'Refresh 1'
  393. 'Refresh 2'
  394. /*'Message' "Finished"*/
  395. /*indicate the main script is finished*/
  396. DisplayMsg="Cleaning up ...."||CR||"Exiting"
  397. result=writeln(6Info, DisplayMsg)
  398. if result~=0 then do
  399.     /*Wait 3 seconds*/
  400.     CALL DELAY(150)
  401.     /* close window*/
  402.     result=close(6Info)
  403. end
  404. 'DEFPUBSCREEN("Workbench")'
  405. exit
  406.  
  407. /* Procedures */
  408.  
  409. cellrow: procedure
  410. do
  411.     parse arg cell
  412.     do charpos=2 to length(cell)
  413.     if datatype(substr(cell,charpos,1),n) then return substr(cell,charpos)
  414.     end
  415.     return 0
  416. end
  417. Return
  418.  
  419. cellcol: procedure
  420. do
  421.     parse arg cell
  422.     labels="ABCDEFGHIJKLMNOPQRSTUVWXYZ"
  423.     cell=upper(cell)
  424.     len=length(cell)
  425.     val=0
  426. do charpos=1 to len
  427.     if datatype(substr(cell,charpos,1),n) then
  428.     do cell=reverse(substr(cell,1,charpos-1))
  429.     do x=1 to length(cell)
  430.     val=(26**(x-1))*pos(substr(cell,x,1),labels)+val
  431.     end
  432.     return val
  433.     end
  434.     end
  435.     return 0
  436. end
  437. Return
  438. /* It is important to put the exposed array at the end of the next line */
  439. Sort: procedure expose  NRows data.
  440. L=(xtoy(2,int(log(NRows)/log(2))))-1
  441.     Do Until L<1
  442.     L=trunc(int(L/2))
  443.     Do J=1 to L
  444.             Do K=J+L To NRows By L
  445.             I=K
  446.             dumdat=data.I
  447.             Do while I>L
  448.                 y=I-L
  449.                 If data.y ~> dumdat then Leave
  450.                 data.I=data.y
  451.                 I=I-L
  452.             End
  453.             data.I=dumdat
  454.             End
  455.         End
  456.     End
  457. Return
  458.  
  459. syntax:
  460.      if arg(1)='FAIL' then do
  461.         'Message "Library is unavailable."'
  462.         'DEFPUBSCREEN("Workbench")'
  463.         exit
  464.         end
  465.     'DEFPUBSCREEN("Workbench")'
  466.     exit
  467.  
  468.  
  469.  
  470. Format:  procedure
  471.  
  472.      arg number, before, after
  473.      CallLine = SIGL
  474.      if ~datatype(CallLine, 'N') then CallLine = '??'
  475.  
  476.      /* Make sure we have a number as first (required) argument    */
  477.      if ~datatype(number, 'N') then do
  478.         if number = '' then
  479.            fc = 17     /* Wrong number of arguments           */
  480.         else
  481.            fc = 47     /* Arithmetic conversion error             */
  482.         signal FormatSyntaxError
  483.      end
  484.      num = number + 0
  485.      if before = '' & after = '' then
  486.         return num
  487.      else do
  488.         parse var num integer '.' fraction
  489.         if before = '' then before = length(integer)
  490.         if after = '' then after = length(fraction)
  491.         if ~datatype(before, N) | ~datatype(after, N) then
  492.            do fc = 18
  493.            signal FormatSyntaxError
  494.        end
  495.         if before < length(integer) then do
  496.            fc = 18
  497.            signal FormatSyntaxError
  498.         end
  499.         if after ~= length(fraction) then do
  500.            fraction = trunc(('.'fraction'0') + ('.'copies('0', after)'5'), after)
  501.         if integer<1&integer>-1 then integer=integer
  502.            else integer = integer + (fraction % 1)
  503.            fraction = substr(fraction, 3)
  504.         end
  505.         if fraction >= 0 then
  506.            return right(integer, before)'.'fraction
  507.         else
  508.            return right(integer, before)
  509.      end
  510.  
  511.  FormatSyntaxError:
  512.         if show('F', STDERR) then
  513.            call writeln(STDERR, '+++ Error' fc 'in line' CallLine':' errortext(fc))
  514.         else
  515.            mess='+++ Error' fc 'in line' CallLine':' errortext(fc)
  516.         'Message' mess
  517.         parse source Func .
  518.         if Func = 'FUNCTION' then do
  519.         'DEFPUBSCREEN("Workbench")'
  520.            exit "Err"
  521.         end
  522.         else do
  523.         'DEFPUBSCREEN("Workbench")'
  524.            exit 10
  525.         end
  526.  
  527. NPROB: Procedure Expose P Q PDF
  528.  
  529.     arg Z
  530.     A0=0.5
  531.     A1=0.398942280444
  532.     A2=0.399903438504
  533.     A3=5.75885480458
  534.     A4=29.8213557808
  535.     A5=2.62433121679
  536.     A6=48.6959930692
  537.     A7=5.92885724438
  538.     B0=0.398942280385
  539.     B1=3.8052E-8
  540.     B2=1.00000615302
  541.     B3=3.98064794E-4
  542.     B4=1.98615381364
  543.     B5=0.151679116635
  544.     B6=5.29330324926
  545.     B7=4.8385912808
  546.     B8=15.1508972451
  547.     B9=0.742380924027
  548.     B10=30.789933034
  549.     B11=3.99019417011
  550.     ZABS = ABS(Z)
  551.     Y = A0*Z*Z
  552.     PDF = EXP(-Y)*B0
  553. SELECT
  554.     WHEN (Z>=-1.28) & (Z<=1.28) then DO /*Z BETWEEN -1.28 AND +1.28*/
  555.         Q = A0-ZABS*(A1-A2*Y/(Y+A3-A4/(Y+A5+A6/(Y+A7))))
  556.         IF (Z<0) then do
  557.             P = Q
  558.             Q = 1.0-P
  559.         End
  560.         Else P = 1.0-Q
  561.         RETURN
  562.     End
  563.     WHEN (Z>1.28) & (Z<=12.7) then do /*ZABS BETWEEN 1.28 AND 12.7 */
  564.         Q = PDF/(ZABS-B1+B2/(ZABS+B3+B4/(ZABS-B5+B6/(ZABS+B7-B8/(ZABS+B9+B10/(ZABS+B11))))))
  565.         IF(Z<0) then Do
  566.             P = Q
  567.             Q = 1.0-P
  568.         End
  569.         Else P = 1.0-Q
  570.         RETURN
  571.     End
  572.     WHEN (Z<-1.28) & (Z>=-12.7) then do /*ZABS BETWEEN 1.28 AND 12.7 */
  573.         Q = PDF/(ZABS-B1+B2/(ZABS+B3+B4/(ZABS-B5+B6/(ZABS+B7-B8/(ZABS+B9+B10/(ZABS+B11))))))
  574.         IF(Z<0) then Do
  575.             P = Q
  576.             Q = 1.0-P
  577.         End
  578.         Else P = 1.0-Q
  579.         RETURN
  580.     End
  581.     OTHERWISE /*Z FAR OUT IN TAIL*/
  582.         Q = 0
  583.         PDF = 0
  584.         IF(Z<0) then do
  585.             P = Q
  586.             Q = 1.0-P
  587.         End
  588.         Else P = 1.0
  589.         RETURN
  590. End
  591. Return
  592.  
  593. CHIPROB: PROCEDURE
  594.  
  595.     PARSE ARG X2,K1
  596.     X3=0.5*X2
  597.     K3=0.5*K1
  598.     X=K3+1
  599.     LG=LOGGAMMA(X)
  600.     S=0
  601.     A=EXP(K3*LN(X3)-LG-X3)
  602.     IF A~=0 THEN DO
  603.         T=1
  604.         S=1
  605.         G=K3
  606.         DO WHILE (T/S) >.000001
  607.             G=G+1
  608.             T=T*X3/G
  609.             S=S+T
  610.         END
  611.     END
  612.     PO=S*A
  613. RETURN PO
  614.  
  615. CHICRIT: PROCEDURE
  616.  
  617.     PARSE ARG PO,K1
  618.     AO=.0001
  619.     E=.005
  620.     E2=E+E
  621.     PA=PO
  622.     SELECT
  623.     WHEN K1=1 THEN DO
  624.         PO=.5+PA/2
  625.         Z=NORMALPP(PO)
  626.         X1=Z*Z
  627.     END
  628.     WHEN K1=2 THEN DO
  629.         X1=1-PA
  630.         X1=-2*LN(X1)
  631.     END
  632.     OTHERWISE
  633.         Z=NORMALPP(PO)
  634.         A1=2/(9*K1)
  635.         W=1-A1+Z*SQRT(A1)
  636.         XO=K1*(W**3)
  637.         DO FOREVER
  638.             X2=XO
  639.             PO=CHIPROB(X2,K1)
  640.             F1=PO-PA
  641.             X2=XO+E
  642.             PO=CHIPROB(X2,K1)
  643.             F2=PO
  644.             X2=XO-E
  645.             PO=CHIPROB(X2,K1)
  646.             F2=F2-PO
  647.             F2=F2/E2
  648.             X1=XO-F1/F2
  649.             IF ABS(X1-XO)>AO THEN XO=X1
  650.             ELSE LEAVE
  651.         END    
  652.     END
  653.     X2=X1
  654. RETURN X2
  655.  
  656. LOGGAMMA: PROCEDURE
  657.  
  658.     ARG XA
  659.     C1=76.18009173
  660.     C2=-86.50532033
  661.     C3=24.01409822
  662.     C4=-1.231739516
  663.     C5=.001208580
  664.     C6=-.000005364
  665.     C7=2.506628275
  666.     X1=XA-1
  667.     W=X1+5.5
  668.     W=(X1+.5)*LN(W)-W
  669.     S=1+C1/(X1+1)+C2/(X1+2)+C3/(X1+3)
  670.     S=S+C4/(X1+4)+C5/(X1+5)+C6/(X1+6)
  671.     L=W+LN(C7*S)
  672. RETURN L
  673.  
  674. NORMALPP: PROCEDURE
  675.  
  676.     ARG P0
  677.     A1=2.515517
  678.     A2=.802853
  679.     A3=.010328
  680.     A4=1.432788
  681.     A5=.189269
  682.     A6=.001308
  683.     Q=.5-ABS(P0-.5)
  684.     SN=SIGN(-2*LN(Q))
  685.     IF SN=-1 THEN W=-1*SQRT(ABS(-2*LN(Q))
  686.     ELSE W=SQRT(-2*LN(Q))
  687.     W1=A1+W*(A2+A3*W)
  688.     W2=1+W*(A4+W*(A5+A6*W))
  689.     ZZ=W-W1/W2
  690.     SELECT
  691.         WHEN (P0-.5)<0 THEN TT=-1
  692.         WHEN (P0-.5)=0 THEN TT=0
  693.         otherwise TT=1
  694.     END
  695.     ZZ=ZZ*TT
  696. RETURN ZZ
  697.